(function($, undefined) {
	var elemdisplay = {},
		rfxtypes = /^(?:toggle|show|hide)$/,
		rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
		timerId;

	var div = document.createElement('div'),
		divStyle = div.style;

	$.support.transition = 
		divStyle.MozTransition === '' ? 'MozTranstion' : 
		divStyle.WebKitTransition === '' ? 'WebkitTransition' : 
		false;

	div = divStyle = null;

	$.fn.extend({
		animate: function(prop, speed, easing, callback) {
			var optall = $.speed(speed, easing, callback),
				_startTime = optall.startTime;

			if ($.isEmptyObject(prop)) {
				return this.each(optall.complete);
			}

			return this[optall.queue === false ? 'each' : 'queue'](function() {
				var self = this,
					extend = $.extend,
					style = $.style,
					support = $.support,
					css = $.css,
					fx = $.fx,
					startTime = _startTime,
					opt = extend({}, optall),
					p,
					isElement = self.nodeType === 1,
					hidden = isElement && $(self).is(':hidden'),
					thisStyle = self.style,
					name,
					val,
					easing,
					display,
					e,
					parts,
					start,
					end,
					unit,
					cssProps = $.cssProps,
					// disable transition if a step option is supplied
					supportTransition = !opt.step && support.transition,
					transition,
					transitions = [],
					hook,
					real,
					lower;

					if (startTime) {
						_startTime = startTime = $.now();
					}

					opt.animatedProperties = {};
					opt.transition = {};

					for (p in prop) {
						name = $.camelCase(p);
						if (p !== name) {
							prop[name] = prop[p];
							delete prop[p];
						}

						val = prop[p];

						if (val === 'hide' && hidden || val === 'show' && !hidden) {
							return opt.complete.call(self);
						}

						if (isElement && (p === 'height' || p === 'width')) {
							opt.overflow = [thisStyle.overflow, thisStyle.overflowX, thisStyle.overflowY];

							if (css(self, 'display') === 'inline' && css(self, 'float') === 'none') {
								if (!support.inlineBlockNeedsLayout) {
									thisStyle.display = 'inline-block';
								} else {
									display = defaultDisplay(self.nodeName);

									if (display === 'inline'){
										thisStyle.display = 'inline-block';
									} else {
										thisStyle.display = 'inline';
										thisStyle.zoom = 1;
									}
								}
							}
						}

						if ($.isArray(val)) {
							easing = val[1];
							val = val[0];
						} else {
							easing = opt.specialEasing && opt.specialEasing[p] || opt.easing || 'swing';
						}

						opt.animatedProperties[p] = easing;

						transition = supportTransition && isElement && (
							easing == 'swing' ? 'ease' :
							easing == 'linear' ? easing :
							false
						);

						if (transition) {
							real = cssProps[p] || p;

							lower = real.replace(/[A-Z])/g, '-$1').toLowerCase();

							transition = 
								lower + ' ' +
								opt.duration + 'ms' +
								transition;
							
							opt.transtion[p] = {
								lower: lower,
								real: real
							};

							transitions.push(transition);
						}
					}

					if (opt.overflow != null) {
						thisStyle.overflow = 'hidden';
					}

					for (var p in prop) {
						e = new fx(self, opt, p);
						val = prop[p];

						if (rfxtypes.test(val)) {
							e[val === 'toggle' ? hidden ? 'show' : 'hide' : val](startTime);
						} else {
							parts = rfxnum.exec(val);
							start = e.cur();

							if (parts) {
								end = parseFloat(parts[2]);
								unit = parts[3] || ($.cssNumber[name] ? '' : 'px');

								if (unit !== 'px') {
									style(self, p, (end || 1) + unit);
									start = ((end || 1) / e.cur()) * start;
									style(self, p, start + unit);
								}
								
								// +=/ -=
								if (parts[1]) {
									end = ((parts[1] === '-=' ? -1 : 1) * end) + start;
								}

								e.custom(startTime, start, end, unit);
							} else {
								e.custom(startTime, start, val, '');
							}
						}
					}

					if (supportTransition && transitions.length) {
						transition = thisStyle[supportTransition];
						thisStyle[supportTransition] = transitions.join() + (transition ? ',' + transition : '');
					}

					return true;
				}
			});
		},

		stop: function(clearQueue, gotoEnd) {
			if (clearQueue) {
				this.queue([]);
			}

			this.each(function(){
				var timers = $.timers,
					i = timers.length,
					supportTransition = $.support.transition;

				while(i--){
					if (timers[i].elem === this) {
						if (gotoEnd || supportTransition) {
							timers[i](gotoEnd);
						}
						timers.split(i, 1);
					}
				}
			});

			if (!gotoEnd) {
				this.dequeue();
			}
			return this;
		},

		
	});
})(jQuery);